const Koa = require("koa");
const router = require("koa-router")();
const nodemailer = require("nodemailer");

const app = new Koa();
const UserModel = require("./models/UserModel");
const TokenModel = require("./models/TokenModel");
const DocModel_1 = require("./models/DocModel_1");
const DocModel_2 = require("./models/DocModel_2");
const DocModel_3 = require("./models/DocModel_3");
const EmailCode = require("./models/EmailCode");
const ContentsModel = require("./models/ContentsModel");
const TagModel = require("./models/TagModel");
const cors = require("koa2-cors");
const bodyParser = require("koa-bodyparser");
var CryptoJS = require("crypto-js");
//upload
const { koaBody } = require("koa-body");
const static = require("koa-static");
const fs = require("fs");
const path = require("path");
// app.use(static(`${process.cwd()}/static`));
app.use(koaBody({
  multipart: true,
  formidable: {
    maxFileSize: 200 * 1024 * 1024,
    keepExtension: true
  }
}));

router.get("/doc1", async ctx => {
  console.log('Query doc1...', ctx.query)
  let uname = ctx.query.username;
  let tk = ctx.query.token;

  let pageSize = 5;
  let curPage = ctx.query.page;
  // console.log("curPage request: " + curPage)
  let maxPage = 0;
  let sum = 0;

  let data = await TokenModel.findOne({ username: uname, token: tk });
  let user = await UserModel.findOne({ username: uname });
  let dayMills = 24 * 60 * 60 * 1000;
  // token 在创建后5天有效，三天后调此接口可以刷新token
  if (data != null && (Date.now() - parseInt(data.timeMills)) < 5 * dayMills) {
    let query = {};
    // 管理员可以获取全部文档，普通用户只能获取自己创建的文档
    if (!user.admin) {
      query.author = uname;
    }

    // 查询总数
    await DocModel_1.countDocuments(query)
      .then(sm => {
        sum = sm;
      })
      .catch(err => {
        console.error('查询总数失败', err);
      });
    let they = [];
    if (sum > 0) {
      maxPage = Math.ceil(sum / pageSize);
      console.log("curPage inner: " + curPage)

      if (!curPage) {
        // 默认最后一页
        curPage = maxPage;
      }
      they = await await DocModel_1.find(query)
        .skip((curPage - 1) * pageSize)
        .limit(pageSize);;
    }
    // console.log(they);
    // console.log("curPage: " + curPage)
    // console.log("maxPage: " + maxPage)
    ctx.body = {
      code: 200,
      res: they,
      curPage,
      maxPage,
      msg: "GET success"
    };
  } else {
    ctx.body = {
      code: 400,
      msg: "登陆过期，请重新登陆"
    };
  }
  console.log('done');
})

router.get("/doc2", async ctx => {
  console.log('Query doc2...', ctx.query)
  let uname = ctx.query.username;
  let tk = ctx.query.token;

  let pageSize = 5;
  let curPage = ctx.query.page;
  // console.log("curPage request: " + curPage)
  let maxPage = 0;
  let sum = 0;

  let data = await TokenModel.findOne({ username: uname, token: tk });
  let user = await UserModel.findOne({ username: uname });
  let dayMills = 24 * 60 * 60 * 1000;
  // token 在创建后5天有效，三天后调此接口可以刷新token
  if (data != null && (Date.now() - parseInt(data.timeMills)) < 5 * dayMills) {
    let query = {};
    // 管理员可以获取全部文档，普通用户只能获取自己创建的文档
    if (!user.admin) {
      query.author = uname;
    }
    // 查询总数
    await DocModel_2.countDocuments(query)
      .then(sm => {
        sum = sm;
      })
      .catch(err => {
        console.error('查询总数失败', err);
      });
    let they = [];
    if (sum > 0) {
      maxPage = Math.ceil(sum / pageSize);
      // console.log("curPage inner: " + curPage)

      if (!curPage) {
        // 默认最后一页
        curPage = maxPage;
      }
      they = await await DocModel_2.find(query)
        .skip((curPage - 1) * pageSize)
        .limit(pageSize);;
    }

    // console.log(they);
    ctx.body = {
      code: 200,
      res: they,
      curPage,
      maxPage,
      msg: "GET success"
    };
  } else {
    ctx.body = {
      code: 400,
      msg: "登陆过期，请重新登陆"
    };
  }
})

router.get("/doc3", async ctx => {
  console.log('Query doc3...', ctx.query)
  let uname = ctx.query.username;
  let tk = ctx.query.token;
  let pageSize = 5;
  let curPage = ctx.query.page;
  // console.log("curPage request: " + curPage)
  let maxPage = 0;
  let sum = 0;
  let data = await TokenModel.findOne({ username: uname, token: tk });
  let user = await UserModel.findOne({ username: uname });
  let dayMills = 24 * 60 * 60 * 1000;
  // token 在创建后5天有效，三天后调此接口可以刷新token
  if (data != null && (Date.now() - parseInt(data.timeMills)) < 5 * dayMills) {
    let query = {};
    // 管理员可以获取全部文档，普通用户只能获取自己创建的文档
    if (!user.admin) {
      query.author = uname;
    }
    // 查询总数
    await DocModel_3.countDocuments(query)
      .then(sm => {
        sum = sm;
      })
      .catch(err => {
        console.error('查询总数失败', err);
      });
    let they = [];
    if (sum > 0) {
      maxPage = Math.ceil(sum / pageSize);
      // console.log("curPage inner: " + curPage)

      if (!curPage) {
        // 默认最后一页
        curPage = maxPage;
      }
      they = await await DocModel_3.find(query)
        .skip((curPage - 1) * pageSize)
        .limit(pageSize);;
    }
    // console.log(they);
    ctx.body = {
      code: 200,
      curPage,
      maxPage,
      res: they,
      msg: "GET success"
    };
  } else {
    ctx.body = {
      code: 400,
      msg: "登陆过期，请重新登陆"
    };
  }
})

router.post("/chapters", async ctx => {
  console.log('Query chapters body:', ctx.request.body)
  const uname = ctx.request.body.username;
  const tk = ctx.request.body.token;
  let type = ctx.request.body.type;
  ctx.set('Content-Type', 'application/json');
  let data = await TokenModel.findOne({ username: uname, token: tk });
  let dayMills = 24 * 60 * 60 * 1000;
  // token 在创建后5天有效，三天后调此接口可以刷新token
  if (data != null && (Date.now() - parseInt(data.timeMills)) < 5 * dayMills) {
    console.log("token valid, save data...");
    let contents = await ContentsModel.find({
      subjectType: { $bitsAllSet: parseInt(type) }
    })
    if (contents) {
      ctx.body = {
        code: 200,
        res: contents,
        msg: "success"
      };
    } else {
      ctx.body = {
        code: 401,
        msg: "查询异常"
      };
    }
  } else {
    ctx.body = {
      code: 400,
      msg: "登陆过期，请重新登陆"
    };
  }
})

router.post("/tags", async ctx => {
  console.log('Query tags body:', ctx.request.body)
  const uname = ctx.request.body.username;
  const tk = ctx.request.body.token;
  let type = ctx.request.body.type;
  let parentName = ctx.request.body.parent;
  let lv = parseInt(ctx.request.body.lv) + 1;
  ctx.set('Content-Type', 'application/json');
  let data = await TokenModel.findOne({ username: uname, token: tk });
  let dayMills = 24 * 60 * 60 * 1000;
  // token 在创建后5天有效，三天后调此接口可以刷新token
  if (data != null && (Date.now() - parseInt(data.timeMills)) < 5 * dayMills) {
    console.log("token valid, save data...");
    let tags = await TagModel.find({
      subjectType: { $bitsAllSet: parseInt(type) },
      parent: parentName,
      lv
    })
    if (tags) {
      ctx.body = {
        code: 200,
        res: tags,
        msg: "success"
      };
    } else {
      ctx.body = {
        code: 401,
        msg: "查询异常"
      };
    }
  } else {
    ctx.body = {
      code: 400,
      msg: "登陆过期，请重新登陆"
    };
  }
})

router.post("/checkCount", async ctx => {
  console.log('checkCount body:', ctx.request.body)
  const uname = ctx.request.body.username;
  const tk = ctx.request.body.token;
  let type = ctx.request.body.type;
  let title = ctx.request.body.title;
  let lv = parseInt(ctx.request.body.lv);
  ctx.set('Content-Type', 'application/json');
  let data = await TokenModel.findOne({ username: uname, token: tk });
  let dayMills = 24 * 60 * 60 * 1000;
  // token 在创建后5天有效，三天后调此接口可以刷新token
  if (data != null && (Date.now() - parseInt(data.timeMills)) < 5 * dayMills) {
    console.log("token valid, save data...");
    let count = -1;
    switch (lv) {
      case 1:
        count = await DocModel_1.countDocuments({
          subjectType: { $bitsAllSet: parseInt(type) },
          title
        });
        break;
      case 2:
        count = await DocModel_2.countDocuments({
          subjectType: { $bitsAllSet: parseInt(type) },
          title
        });
        break;
      case 3:
        count = await DocModel_3.countDocuments({
          subjectType: { $bitsAllSet: parseInt(type) },
          title
        });
        break;
      default:
        break;
    }
    if (count > -1) {
      ctx.body = {
        code: 200,
        count,
        msg: "success"
      };
    } else {
      // ctx.body = {
      //   code: 401,
      //   msg: "查询异常"
      // };
      ctx.body = {
        code: 200,
        count: 0,
        msg: "查询异常"
      };
    }
  } else {
    ctx.body = {
      code: 400,
      msg: "登陆过期，请重新登陆"
    };
  }
})

router.post("/pickModel", async ctx => {
  console.log('pickModel body:', ctx.request.body)
  const uname = ctx.request.body.username;
  const tk = ctx.request.body.token;
  let type = ctx.request.body.type;
  let title = ctx.request.body.title;
  let lv = parseInt(ctx.request.body.lv);
  ctx.set('Content-Type', 'application/json');
  let data = await TokenModel.findOne({ username: uname, token: tk });
  let dayMills = 24 * 60 * 60 * 1000;
  // token 在创建后5天有效，三天后调此接口可以刷新token
  if (data != null && (Date.now() - parseInt(data.timeMills)) < 5 * dayMills) {
    console.log("token valid");
    let ret;
    let model;
    switch (lv) {
      case 1:
        model = DocModel_1;
        break;
      case 2:
        model = DocModel_2;
        break;
      case 3:
        model = DocModel_3;
        break;
    }
    if (model) {
      await model.aggregate([
        {
          $match: {
            subjectType: { $bitsAllSet: parseInt(type) },
            title
          }
        },
        { $sample: { size: 1 } }
      ])
        .exec()
        .then(result => {
          ret = result?.[0] ?? null;
        })
        .catch(error => {
          console.error(error);
        });
    }
    ctx.body = {
      code: 200,
      res: ret,
      msg: "success"
    };

  } else {
    ctx.body = {
      code: 400,
      msg: "登陆过期，请重新登陆"
    };
  }
})


router.post("/register", async ctx => {
  console.log(ctx.request.body);
  var uname = ctx.request.body.username;
  var psw = ctx.request.body.psw;
  var pswMD5 = CryptoJS.MD5(psw).toString();
  var data = await UserModel.find({ username: uname });
  ctx.set('Content-Type', 'application/json');
  if (data.length > 0) {
    ctx.body = JSON.stringify({
      code: 400,
      msg: '已存在的用户名,试试别的吧'
    });
  } else {
    var admin = uname === "admin";
    const person = await UserModel.create({
      username: uname,
      password: pswMD5,
      fullname: 'none',
      phone: 'none',
      email: 'none',
      admin: admin
    });
    console.log(person);
    ctx.body = JSON.stringify({
      code: 200,
      msg: "注册成功"
    });
  }
});

router.post("/login", async ctx => {
  console.log("login:" + ctx.request.body.username);
  var uname = ctx.request.body.username;
  var psw = ctx.request.body.psw;
  var pswMD5 = CryptoJS.MD5(psw).toString();
  var data = await UserModel.find({ username: uname, password: pswMD5 });
  if (data.length > 0) {
    const tm = Date.now();
    const tk = await TokenModel.create({
      username: uname,
      token: CryptoJS.MD5(uname + tm).toString(),
      timeMills: tm
    });
    ctx.body = {
      code: 200,
      token: tk.token,
      admin: data[0].admin,
      msg: "登陆成功"
    };
  } else {
    ctx.body = {
      code: 404,
      msg: "用户名或密码错误"
    };
  }
});

router.post("/checkToken", async ctx => {
  console.log("checkToken: ");
  console.log(ctx.request.body);
  var uname = ctx.request.body.username;
  var tk = ctx.request.body.token;
  var data = await TokenModel.findOne({ username: uname, token: tk });
  var dayMills = 24 * 60 * 60 * 1000;
  // token 在创建后5天有效，三天后调此接口可以刷新token
  if (data != null && (Date.now() - parseInt(data.timeMills)) < 5 * dayMills) {
    var newToken = "";
    if ((Date.now() - parseInt(data.timeMills)) > 3 * dayMills) {
      await TokenModel.deleteOne({ username: uname, token: tk });
      const tm = Date.now();
      // const tk = await TokenModel.create({
      //   username: uname,
      //   token: CryptoJS.MD5(uname + tm).toString(),
      //   timeMills: tm
      // })

      const newData = {
        username: uname,
        token: CryptoJS.MD5(uname + tm).toString(),
        timeMills: tm
      };
      await TokenModel.findOneAndUpdate(
        { username: uname }, // 查询条件
        newData, // 更新的数据
        // 选项：upsert - 若文档不存在则创建之，new - 返回更新后的文档，runValidators - 运行验证器以应用模型定义的验证规则
        { upsert: true, new: true, runValidators: true })
        .then(ret => {
          console.log('User token updated.');
        })
        .catch(err => {
          console.error('User token update error:', err);
        });
      newToken = tk.token
    }
    ctx.body = {
      code: 200,
      token: newToken,
      msg: "token有效"
    };
  } else {
    await TokenModel.deleteMany({ username: uname, token: tk });
    ctx.body = {
      code: 400,
      msg: "登陆过期，请重新登陆"
    };
  }
});

router.post("/commitDoc1", async ctx => {
  console.log("commitDoc1  body: ", ctx.request.body);
  var uname = ctx.request.body.username;
  var tk = ctx.request.body.token;
  var data = await TokenModel.findOne({ username: uname, token: tk });
  var dayMills = 24 * 60 * 60 * 1000;
  // token 在创建后5天有效，三天后调此接口可以刷新token
  if (data != null && (Date.now() - parseInt(data.timeMills)) < 5 * dayMills) {
    console.log("token valid, save data...");
    let newData = {
      subjectType: ctx.request.body.subjectType,
      title: ctx.request.body.title,
      content: ctx.request.body.content,
      author: ctx.request.body.username,
    }

    let code = 0;
    let msg = "";
    let query = {};
    let count = 0;
    if (ctx.request.body._id) {
      query._id = ctx.request.body._id;
      count = await DocModel_1.countDocuments({
        _id: ctx.request.body._id,
      });
    }
    let ret;
    if (count < 1) {
      // check 70%
      let checkRet = await check70(DocModel_1, newData.subjectType, newData.title, newData.content)
      if (checkRet.isSame) {
        ctx.body = {
          code: 407,
          doc: checkRet.doc,
          msg: '提交失败，与已有模版重复'
        };
        return;
      }
      newData.timeMills = Date.now();
      await DocModel_1.create(newData).then(doc => {
        // 更新或插入成功后的操作
        console.log('commitDoc1 success:', doc._id);
        ret = doc;
        code = 200;
        msg = '新建成功';
      })
        .catch(err => {
          console.error("commitDoc1 create err: " + err);
          code = 403;
          msg = '数据新建异常';
        });
    } else {
      // check 70%
      let checkRet = await check70(DocModel_1, newData.subjectType, newData.title, newData.content, query._id)
      if (checkRet.isSame) {
        ctx.body = {
          code: 407,
          doc: checkRet.doc,
          msg: '提交失败，已有模版重复'
        };
        return;
      }
      await DocModel_1.findOneAndUpdate(
        query, // 查询条件
        newData, // 更新的数据
        // 选项：upsert - 若文档不存在则创建之，new - 返回更新后的文档，runValidators - 运行验证器以应用模型定义的验证规则
        { upsert: true, new: true, runValidators: true })
        .then(doc => {
          // 更新或插入成功后的操作
          console.log('commitDoc1 success:', doc._id);
          ret = doc;
          code = 200;
          msg = '修改成功';
        })
        .catch(err => {
          // 错误处理
          console.error("commitDoc1 findOneAndUpdate err: " + err);
          code = 403;
          msg = '数据修改异常';
        });
    }
    ctx.body = {
      code,
      ret,
      msg
    };
  } else {
    ctx.body = {
      code: 400,
      msg: "登陆过期，请重新登陆"
    };
  }
});

function similarity(str1, str2) {
  const len1 = str1.length;
  const len2 = str2.length;
  const matrix = [];

  if (len1 === 0) return len2;
  if (len2 === 0) return len1;

  for (let i = 0; i <= len1; i++) {
    matrix[i] = [i];
  }

  for (let j = 0; j <= len2; j++) {
    matrix[0][j] = j;
  }

  for (let i = 1; i <= len1; i++) {
    for (let j = 1; j <= len2; j++) {
      const cost = str1[i - 1] === str2[j - 1] ? 0 : 1;
      matrix[i][j] = Math.min(
        matrix[i - 1][j] + 1, // deletion
        matrix[i][j - 1] + 1, // insertion
        matrix[i - 1][j - 1] + cost // substitution
      );
    }
  }

  const distance = matrix[len1][len2];
  const similarity = (1 - distance / Math.max(len1, len2)) * 100;
  return similarity;
}

async function check70(model, type, title, content, id) {
  // check 70%
  let same70 = false;
  let sameDoc = {};
  let matchObj = {
    subjectType: { $bitsAllSet: parseInt(type) },
    title
  };
  await model.aggregate([
    { $match: matchObj }
  ])
    .exec()
    .then(li => {
      console.log('check70 len:', li?.length);
      if (li?.length > 0) {
        for (let el of li) {
          if (el._id.toString() === id) {
            continue
          }
          if (similarity(content, el.content) >= 70) {
            same70 = true;
            sameDoc = el;
            break;
          }
        }
      }
    })
    .catch(error => {
      console.error(error);
    });
  return {
    isSame: same70,
    doc: sameDoc,
  };
}

router.post("/delDoc1", async ctx => {
  console.log("delDoc1  body: ", ctx.request.body);
  var uname = ctx.request.body.username;
  var tk = ctx.request.body.token;
  var data = await TokenModel.findOne({ username: uname, token: tk });
  var dayMills = 24 * 60 * 60 * 1000;
  // token 在创建后5天有效，三天后调此接口可以刷新token
  if (data != null && (Date.now() - parseInt(data.timeMills)) < 5 * dayMills) {
    console.log("token ok, save data...");
    let code = 0;
    let msg = "";
    await DocModel_1.findByIdAndDelete(
      ctx.request.body._id)
      .then(doc => {
        // 更新或插入成功后的操作
        console.log('delDoc1 success');
        _id = doc._id;
        code = 200;
        msg = '删除成功';
      })
      .catch(err => {
        // 错误处理
        console.error("delDoc1 findOneAndUpdate err: " + err);
        code = 403;
        msg = '删除异常';
      });
    ctx.body = {
      code,
      _id,
      msg
    };
  } else {
    ctx.body = {
      code: 400,
      msg: "登陆过期，请重新登陆"
    };
  }
});

router.post("/commitDoc2", async ctx => {
  console.log("commitDoc2  body: ", ctx.request.body);
  var uname = ctx.request.body.username;
  var tk = ctx.request.body.token;
  var data = await TokenModel.findOne({ username: uname, token: tk });
  var dayMills = 24 * 60 * 60 * 1000;
  // token 在创建后5天有效，三天后调此接口可以刷新token
  if (data != null && (Date.now() - parseInt(data.timeMills)) < 5 * dayMills) {
    console.log("token valid, save data...");
    let newData = {
      subjectType: ctx.request.body.subjectType,
      title: ctx.request.body.title,
      content: ctx.request.body.content,
      author: ctx.request.body.username,
    }

    let code = 0;
    let msg = "";
    let query = {};
    let count = 0;
    if (ctx.request.body._id) {
      query._id = ctx.request.body._id;
      count = await DocModel_2.countDocuments({
        _id: ctx.request.body._id,
      });
    }
    let ret;
    if (count < 1) {

      newData.timeMills = Date.now();
      await DocModel_2.create(newData).then(doc => {
        // 更新或插入成功后的操作
        console.log('commitDoc2 success:', doc._id);
        ret = doc;
        code = 200;
        msg = '新建成功';
      })
        .catch(err => {
          console.error("commitDoc2 create err: " + err);
          code = 403;
          msg = '数据新建异常';
        });
    } else {
      await DocModel_2.findOneAndUpdate(
        query, // 查询条件
        newData, // 更新的数据
        // 选项：upsert - 若文档不存在则创建之，new - 返回更新后的文档，runValidators - 运行验证器以应用模型定义的验证规则
        { upsert: true, new: true, runValidators: true })
        .then(doc => {
          // 更新或插入成功后的操作
          console.log('commitDoc2 success:', doc._id);
          ret = doc;
          code = 200;
          msg = '修改成功';
        })
        .catch(err => {
          // 错误处理
          console.error("commitDoc2 findOneAndUpdate err: " + err);
          code = 403;
          msg = '数据修改异常';
        });
    }
    ctx.body = {
      code,
      ret,
      msg
    };

  } else {
    ctx.body = {
      code: 400,
      msg: "登陆过期，请重新登陆"
    };
  }
});

router.post("/delDoc2", async ctx => {
  console.log("delDoc2  body: ", ctx.request.body);
  var uname = ctx.request.body.username;
  var tk = ctx.request.body.token;
  var data = await TokenModel.findOne({ username: uname, token: tk });
  var dayMills = 24 * 60 * 60 * 1000;
  // token 在创建后5天有效，三天后调此接口可以刷新token
  if (data != null && (Date.now() - parseInt(data.timeMills)) < 5 * dayMills) {
    console.log("token ok, save data...");
    let code = 0;
    let msg = "";
    await DocModel_2.findByIdAndDelete(
      ctx.request.body._id)
      .then(doc => {
        // 更新或插入成功后的操作
        console.log('delDoc1 success');
        _id = doc._id;
        code = 200;
        msg = '删除成功';
      })
      .catch(err => {
        // 错误处理
        console.error("delDoc1 findOneAndUpdate err: " + err);
        code = 403;
        msg = '删除异常';
      });
    ctx.body = {
      code,
      _id,
      msg
    };
  } else {
    ctx.body = {
      code: 400,
      msg: "登陆过期，请重新登陆"
    };
  }
});

router.post("/commitDoc3", async ctx => {
  console.log("commitDoc3  body: ", ctx.request.body);
  var uname = ctx.request.body.username;
  var tk = ctx.request.body.token;
  var data = await TokenModel.findOne({ username: uname, token: tk });
  var dayMills = 24 * 60 * 60 * 1000;
  // token 在创建后5天有效，三天后调此接口可以刷新token
  if (data != null && (Date.now() - parseInt(data.timeMills)) < 5 * dayMills) {
    console.log("token valid, save data...");
    let newData = {
      subjectType: ctx.request.body.subjectType,
      title: ctx.request.body.title,
      content: ctx.request.body.content,
      author: ctx.request.body.username,
    }

    let code = 0;
    let msg = "";
    let query = {};
    let count = 0;
    if (ctx.request.body._id) {
      query._id = ctx.request.body._id;
      count = await DocModel_3.countDocuments({
        _id: ctx.request.body._id,
      });
    }
    let ret;
    if (count < 1) {
      newData.timeMills = Date.now();
      await DocModel_3.create(newData).then(doc => {
        // 更新或插入成功后的操作
        console.log('commitDoc3 success:', doc._id);
        ret = doc;
        code = 200;
        msg = '新建成功';
      })
        .catch(err => {
          console.error("commitDoc3 create err: " + err);
          code = 403;
          msg = '数据新建异常';
        });
    } else {
      await DocModel_3.findOneAndUpdate(
        query, // 查询条件
        newData, // 更新的数据
        // 选项：upsert - 若文档不存在则创建之，new - 返回更新后的文档，runValidators - 运行验证器以应用模型定义的验证规则
        { upsert: true, new: true, runValidators: true })
        .then(doc => {
          // 更新或插入成功后的操作
          console.log('commitDoc3 success:', doc._id);
          ret = doc;
          code = 200;
          msg = '修改成功';
        })
        .catch(err => {
          // 错误处理
          console.error("commitDoc3 findOneAndUpdate err: " + err);
          code = 403;
          msg = '数据修改异常';
        });
    }
    ctx.body = {
      code,
      ret,
      msg
    };

  } else {
    ctx.body = {
      code: 400,
      msg: "登陆过期，请重新登陆"
    };
  }
});

router.post("/delDoc3", async ctx => {
  console.log("delDoc3  body: ", ctx.request.body);
  var uname = ctx.request.body.username;
  var tk = ctx.request.body.token;
  var data = await TokenModel.findOne({ username: uname, token: tk });
  var dayMills = 24 * 60 * 60 * 1000;
  // token 在创建后5天有效，三天后调此接口可以刷新token
  if (data != null && (Date.now() - parseInt(data.timeMills)) < 5 * dayMills) {
    console.log("token ok, save data...");
    let code = 0;
    let msg = "";
    await DocModel_3.findByIdAndDelete(
      ctx.request.body._id)
      .then(doc => {
        // 更新或插入成功后的操作
        console.log('delDoc3 success', doc._id);
        _id = doc._id;
        code = 200;
        msg = '删除成功';
      })
      .catch(err => {
        // 错误处理
        console.error("delDoc3 findOneAndUpdate err: " + err);
        code = 403;
        msg = '删除异常';
      });
    ctx.body = {
      code,
      _id,
      msg
    };
  } else {
    ctx.body = {
      code: 400,
      msg: "登陆过期，请重新登陆"
    };
  }
});

router.post("/verifyDoc1", async ctx => {
  console.log("verifyDoc1: ");
  var uname = ctx.request.body.username;
  var tk = ctx.request.body.token;
  var data = await TokenModel.findOne({ username: uname, token: tk });
  let user = await UserModel.findOne({ username: uname });
  if (!user.admin) {
    ctx.body = {
      code: 403,
      msg: "需要管理员权限"
    };
    return;
  }
  var dayMills = 24 * 60 * 60 * 1000;
  if (data != null && (Date.now() - parseInt(data.timeMills)) < 5 * dayMills) {
    console.log("token valid, save data...");
    await DocModel_1.findOneAndUpdate(
      { _id: ctx.request.body._id }, // 查询条件
      { $set: { pass: ctx.request.body.pass } }, // 更新的数据
      { upsert: true, new: true, runValidators: true })
      .then(ret => {
        console.log('verifyDoc1 success');
        ctx.body = {
          code: 200,
          msg: "提交成功"
        };
      })
      .catch(err => {
        console.error("verifyDoc1 findOneAndUpdate err: " + err);
        ctx.body = {
          code: 403,
          msg: "数据更新失败" + err
        };
      });
  } else {
    ctx.body = {
      code: 400,
      msg: "登陆过期，请重新登陆"
    };
  }
});

router.post("/verifyDoc2", async ctx => {
  console.log("verifyDoc2: ");
  var uname = ctx.request.body.username;
  var tk = ctx.request.body.token;
  var data = await TokenModel.findOne({ username: uname, token: tk });
  let user = await UserModel.findOne({ username: uname });
  if (!user.admin) {
    ctx.body = {
      code: 403,
      msg: "需要管理员权限"
    };
    return;
  }
  var dayMills = 24 * 60 * 60 * 1000;
  if (data != null && (Date.now() - parseInt(data.timeMills)) < 5 * dayMills) {
    console.log("token valid, save data...");
    await DocModel_2.findOneAndUpdate(
      { _id: ctx.request.body._id }, // 查询条件
      { $set: { pass: ctx.request.body.pass } }, // 更新的数据
      { upsert: true, new: true, runValidators: true })
      .then(ret => {
        console.log('verifyDoc2 success');
        ctx.body = {
          code: 200,
          msg: "提交成功"
        };
      })
      .catch(err => {
        console.error("verifyDoc2 findOneAndUpdate err: " + err);
        ctx.body = {
          code: 403,
          msg: "数据更新失败" + err
        };
      });
  } else {
    ctx.body = {
      code: 400,
      msg: "登陆过期，请重新登陆"
    };
  }
});

router.post("/verifyDoc3", async ctx => {
  console.log("verifyDoc3: ");
  var uname = ctx.request.body.username;
  var tk = ctx.request.body.token;
  var data = await TokenModel.findOne({ username: uname, token: tk });
  let user = await UserModel.findOne({ username: uname });
  if (!user.admin) {
    ctx.body = {
      code: 403,
      msg: "需要管理员权限"
    };
    return;
  }
  var dayMills = 24 * 60 * 60 * 1000;
  if (data != null && (Date.now() - parseInt(data.timeMills)) < 5 * dayMills) {
    console.log("token valid, save data...");
    let code = 0;
    let msg = "";
    await DocModel_3.findOneAndUpdate(
      { _id: ctx.request.body._id }, // 查询条件
      { $set: { pass: ctx.request.body.pass } }, // 更新的数据
      { upsert: true, new: true, runValidators: true })
      .then(doc => {
        // 更新或插入成功后的操作
        console.log('verifyDoc3 success');
        code = 200;
        msg = '提交成功';
      })
      .catch(err => {
        // 错误处理
        console.error("verifyDoc3 findOneAndUpdate err: " + err);
        code = 403;
        msg = '数据保存异常';
      });
    ctx.body = {
      code,
      msg
    };
  } else {
    ctx.body = {
      code: 400,
      msg: "登陆过期，请重新登陆"
    };
  }
});

router.post("/change_name", async ctx => {
  console.log(ctx.request.body);
  var un = ctx.request.body.username;
  var name = ctx.request.body.name;
  var res = await UserModel.updateMany({ username: un }, { fullname: name })
  console.log(res);
  if (res.modifiedCount) {
    ctx.body = {
      code: 200,
      msg: "Change name success"
    };
  }
});

router.post("/uploadQas", async ctx => {
  console.log(ctx.request.body);
  var un = ctx.request.body.username;
  var name = ctx.request.body.name;
  var res = await UserModel.updateMany({ username: un }, { fullname: name })
  console.log(res);
  if (res.modifiedCount) {
    ctx.body = {
      code: 200,
      msg: "Change name success"
    };
  }
});

const transporter = nodemailer.createTransport({
  service: "hotmail",
  auth: {
    user: 'hyc-service@outlook.com',
    pass: 'iwyafcskofvyahoo'
  }
});
router.post("/getEmailCode", async ctx => {
  console.log('getEmailCode start', ctx.request.body);
  var uname = ctx.request.body.username;
  var data = await UserModel.findOne({ username: uname });
  ctx.set('Content-Type', 'application/json');
  if (data) {
    let code = '';
    for (let i = 0; i < 6; i++) {
      code += Math.floor(Math.random() * 10);
    }
    const ecode = await EmailCode.create({
      email: uname,
      code: code,
    });
    // console.log(ecode);
    try {
      const info = await transporter.sendMail({
        from: '"安全码" <hyc-service@outlook.com>', // sender address
        to: uname, // list of receivers
        subject: "账号验证码", // Subject line
        text: "你的邮箱验证码", // plain text body
        html: "<b>" + ("你的验证码是：" + code + "，验证码三分钟内有效。\n如果你没有进行相关操作，请忽略此邮件") + "</b>", // html body
      });
      console.log("Message sent: %s", info.messageId);
      ctx.body = JSON.stringify({
        code: 200,
        msg: "发送验证码成功，请在邮箱查收"
      });
    } catch (err) {
      ctx.body = JSON.stringify({
        code: 400,
        msg: '发送验证码失败'
      });
      console.log("错误信息：" + err);
    }
  } else {
    ctx.body = JSON.stringify({
      code: 400,
      msg: '该用户不存在,请检查用户名'
    });

  }
});

router.post("/resetPsw", async ctx => {
  console.log(ctx.request.body);
  var uname = ctx.request.body.username;
  var psw = ctx.request.body.psw;
  var emailCode = ctx.request.body.emailCode;
  var pswMD5 = CryptoJS.MD5(psw).toString();
  var user = await UserModel.findOne({ username: uname });
  ctx.set('Content-Type', 'application/json');
  if (user) {
    let ecode = await EmailCode.findOne({ code: emailCode });
    let now = Date.now();
    let tsp = new Date(ecode.tsp).getTime();
    if (ecode && ((now - tsp) < 3 * 60 * 1000)) {
      user.password = pswMD5;
      await user.save()
        .then(result => {
          ctx.body = JSON.stringify({
            code: 200,
            msg: '重置密码成功，请登录'
          });
        })
        .catch(err => {
          console.error(err);
          ctx.body = JSON.stringify({
            code: 400,
            msg: '更改密码失败'
          });
        });
    } else {
      ctx.body = JSON.stringify({
        code: 400,
        msg: '无效的验证码'
      });
    }
    await EmailCode.deleteMany({ email: uname })
      .then((result) => {
        console.log(`Deleted EmailCode: ${result}`);
      })
      .catch(error => {
        console.error('delete emailcode fail', error);
      });
  } else {
    ctx.body = JSON.stringify({
      code: 400,
      msg: '该用户不存在,请检查用户名'
    });
  }
});

router.post("/audit", async ctx => {
  console.log(ctx.request.body);
  let uname = ctx.request.body.username;
  let tk = ctx.request.body.token;
  let dataType = ctx.request.body.dataType;
  let docId = ctx.request.body._id;
  let audit = ctx.request.body.audit;
  let data = await TokenModel.findOne({ username: uname, token: tk });
  if (!data) {
    ctx.body = JSON.stringify({
      code: 403,
      msg: '用户验证失败，请重新登录'
    });
    return;
  }
  let user = await UserModel.findOne({ username: uname });
  if (!user.admin) {
    ctx.body = {
      code: 403,
      msg: "需要管理员权限"
    };
    return;
  }
  let model = null;
  switch (dataType) {
    case 1:
      model = DocModel_1;
      break;
    case 2:
      model = DocModel_2;
      break;
    case 3:
      model = DocModel_3;
      break;
  }
  console.log('model', model)
  ctx.set('Content-Type', 'application/json');
  if (model) {
    let doc = await model.findOne({ _id: docId });
    doc.audit = audit;
    doc.auditMills = Date.now();
    await doc.save()
      .then(result => {
        ctx.body = JSON.stringify({
          code: 200,
          msg: '审核意见保存成功'
        });
      })
      .catch(err => {
        console.error(err);
        ctx.body = JSON.stringify({
          code: 400,
          msg: '审核意见保存失败'
        });
      });
  } else {
    ctx.body = JSON.stringify({
      code: 400,
      msg: '数据类型错误'
    });
  }
});

// router.post("/uploadFile", async ctx => {
//   const file = ctx.request.files.file;
//   const basename = path.basename(file.path);
//   const reader = fs.createReadStream(file.path);
//   let filePath = process.cwd() + `/static/${basename}`;
//   const upStream = fs.createWriteStream(filePath);
//   reader.pipe(upStream);
// });

router.get("/", async ctx => {
  const path = require('path');
  const filePath = path.join(__dirname, '/login.html');
  ctx.response.type = 'html';
  ctx.body = fs.readFileSync(filePath);
});

app.use(bodyParser());
app.use(cors({
  origin: function (ctx) {
    return '*';
  }
}));
app.use(router.routes());
app.use(static(`${process.cwd()}`));
app.listen(85);